﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GmPickGroupEventHandle.h"
#include <stack>
#include "IDocument.h"
#include "IPickResult.h"
#include "IGraphicsNodeReference.h"
#include "IPick.h"
#include "IGroup.h"
#include "ILinkElementProxy.h"
#include "ILinkDocumentElement.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

void GmPickGroupEventHandler::Process(gcmp::IDocument* pDoc, gcmp::IPickEventArgs* pArgs, const gcmp::Vector3d& pos) const
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"pDoc参数为空",L"GDMPLab",L"2024-03-30");
    //在项目文档，轮廓编辑模式环境下，需要保证轮廓线，坡度线优先被拾取;
    if (pDoc->IsFamilyDocument())
        return;

    OwnerPtr<IPickResult> pickResult = pArgs->GetPickCandidates().Clone();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pickResult, L"pickResult is nullptr!",L"GDMPLab",L"2024-03-30");
    std::vector<OwnerPtr<IPick>>& allPicks = pickResult->GetAllPicks();
    allPicks.clear();

    OwnerPtr<IPickResult> resultInput = pArgs->GetPickCandidates().Clone();
    DBG_WARN_AND_RETURN_VOID_UNLESS(resultInput, L"resultInput is nullptr!",L"GDMPLab",L"2024-03-30");

    std::vector<OwnerPtr<IPick>>& candidates = resultInput->GetAllPicks();
    UnorderedElementIdSet groupIds;
    for (auto it = candidates.begin(); it != candidates.end(); ++it)
    {
        const gcmp::IGraphicsNodeReference* pNodeReference = (*it)->GetFront();
        if (pNodeReference == nullptr)
        {
            continue;
        }
        
        IElement* pEle = pDoc->GetElement(pNodeReference->GetElementId());
        if (!pEle)
            continue;

        if (IGroup* pGroup = quick_cast<IGroup>(pEle))
        {
            // 组本身;
            if (!pGroup->IsSubElementSnapble())
            {
                // 捕捉到组本身，直接加入选择结果;
                pickResult->AddPick(TransferOwnership(*it));
            }
            continue;
        }

        IGroup* pGroup = nullptr;
        if (ILinkElementProxy* pLinkEleProxy = quick_cast<ILinkElementProxy>(pEle))
        {
            const ILinkDocumentElement* pLinkDocElement = pLinkEleProxy->GetLinkDocumentElement();
            if (pLinkDocElement)
            {
                pGroup = quick_cast<IGroup>(pDoc->GetElement(pLinkDocElement->GetGroupId()));
            }
        }
        else
        {
            pGroup = quick_cast<IGroup>(pDoc->GetElement(pEle->GetGroupId()));
        }

        if (pGroup == nullptr)
        {
            // element不在组内，直接加入选择结果;
            pickResult->AddPick(TransferOwnership(*it));
        }
        else
        {
            // element在组内;
            std::stack<IGroup*> stackParentGroups;
            while (pGroup != nullptr)
            {
                if (pGroup->IsSubElementSnapble())
                {
                    break;
                }
                stackParentGroups.push(pGroup);
                pGroup = quick_cast<IGroup>(pDoc->GetElement(pGroup->GetGroupId()));
            }

            while (!stackParentGroups.empty())
            {
                // 由外向内处理;
                pGroup = stackParentGroups.top();
                stackParentGroups.pop();

                if (pGroup)
                {
                    ElementId groupId = pGroup->GetElementId();
                    if (std::find(groupIds.begin(), groupIds.end(), groupId) == groupIds.end())
                    {
                        OwnerPtr<IGraphicsNodeReference> nodeRef = IGraphicsNodeReference::CreateGraphicsElementShapeReference(groupId);
                        if (!nodeRef || nodeRef.get() == nullptr)
                        {
                            continue;
                        }
                        OwnerPtr<GraphicsNodeAndTransform> originalNodeInfo = pNodeReference->GetIntersectGraphicsNode();
                        if (originalNodeInfo && originalNodeInfo.get())
                        {
                            nodeRef->SetIntersectData(pNodeReference->GetUntransformedIntersectPoint(), (originalNodeInfo->m_wpGraphicsNode).Get(), (originalNodeInfo->m_opTransfrom).get());
                        }
                        OwnerPtr<IPick> opPick = IPick::Create();
                        opPick->AddGraphicsNodeReference(*(nodeRef.get()));
                        pickResult->AddPick(TransferOwnership(opPick));
                        groupIds.emplace(groupId);
                    }
                }
            }
            
            pickResult->AddPick(TransferOwnership(*it));
        }
    }

    pArgs->SetPickCandidates(*pickResult);
}

